package cn.ddiancan.xddcloud.common.security;

import cn.ddiancan.xddcloud.common.context.XddCloudContextUtils;
import cn.ddiancan.xddcloud.common.entity.UserVO;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class JwtService {

    @Value("${xddcloud.jwt.publicKey:}")
    private String publicKey;

    @Value("${xddcloud.jwt.privateKey:}")
    private String privateKey;

    @Value("${xddcloud.jwt.expireTime:30}")
    private int expireTime;

    private RSAPublicKey rsaPublicKey;

    private RSAPrivateKey rsaPrivateKey;

    public UserVO getUserInfo(String token) {
        try {
            checkKeyPublicConfig();
            checkKeyPrivateConfig();
            if (StringUtils.isEmpty(token)) {
                return null;
            }
            if (Objects.isNull(rsaPublicKey)) {
                byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8));
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
            }
            Claims body = Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Object payload = body.get("payload");
            return Objects.isNull(payload) ? null : JSON.parseObject(JSON.toJSONString(payload), UserVO.class);
        } catch (Exception e) {
            log.error("jwt解析出错：{}", e.getMessage(), e);
            return null;
        }
    }

    private void checkKeyPublicConfig() {
        if (!StringUtils.hasText(publicKey)) {
            throw new SecurityException("Empty Rsa public key,you can config [xddcloud.jwt.publicKey] to contiue with");
        }
    }

    private void checkKeyPrivateConfig() {
        if (!StringUtils.hasText(publicKey)) {
            throw new SecurityException(
                "Empty Rsa public key,you can config [xddcloud.jwt.privateKey] to contiue with");
        }
    }

    private void checkKeyToken(String token) {
        if (!StringUtils.hasText(token)) {

        }
    }

    public String createToken(UserVO userInfo) {
        try {
            if (Objects.isNull(rsaPrivateKey)) {
                // 将字符串转换为字节数组
                byte[] privateKeyBates = Base64.getDecoder().decode(privateKey.getBytes(StandardCharsets.UTF_8));
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBates);
                // 获取RSA算法的KeyFactory对象
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                // 生成RSAPublicKey对象
                rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
            }
            Date iat = new Date();
            Date exp = new Date(iat.getTime() + expireTime * 60 * 1000);
            Map<String, Object> header = new HashMap<>(2);
            String application = XddCloudContextUtils.getApplication();
            header.put("Type", "Jwt");
            header.put("alg", "PS512");
            header.put("payload", userInfo);
            return Jwts.builder().setIssuer(application).setClaims(header).setExpiration(exp)
                .signWith(SignatureAlgorithm.PS512, rsaPrivateKey).compact();
        } catch (Exception e) {
            log.error("Error during token generation: " + e.getMessage());
            return null;
        }
    }
}
